
package custom;

import java.io.*;
import java.math.*;
import java.net.*;
import java.util.*;

public class CustomJson
{
    public static void main(String... args){
        System.out.println(CustomJson.export(
            new CustomJson().add(
                "BigDecimal", new BigDecimal(3.1415926535)).add(
                "GoldenRatio", Math.sqrt(5)/2+0.5).add(
                "array", new Object[] {"e1", "e2", "e3", "e4", "e5"}).add(
                "object", new CustomJson().addNull(
                    "nullKey").add(
                    "child", "nothing"))));
    }
    
    public static int TAB_SIZE = 2;
    private static String NEW_LINE = "\n\n";
    public static String STRING_REGEX = "\"(?:\\\\?+.)*?\"";
    public static void load(CustomJson obj, String json){
        //regex for json string: "(?:\\?+.)*?"
        //regex for json string: "([^\\"]|\\\\|\\")*"
    }
    public static String export(CustomJson obj){
        StringBuilder output = new StringBuilder(
                CustomJson.toJsonString(obj));
        String indent = output.toString().replaceAll(
                CustomJson.STRING_REGEX, "").replaceAll(
                "([:\\[\\],e\\.\\d ]|true|false|null)", "");
        int index = 0, index1 = 0;
        while(( index=output.indexOf(CustomJson.NEW_LINE) ) >= 0){
            String str = indent.substring(0,
                    index1=indent.indexOf(CustomJson.NEW_LINE));
            output.replace(index, index+CustomJson.NEW_LINE.length(), "\n"+
                    new String(new char[(str.replaceAll("[^{]", "").length()-
                    str.replaceAll("[^}]", "").length())*CustomJson.TAB_SIZE]
                    ).replaceAll(".", " "));
            indent = str.replace(CustomJson.NEW_LINE, "") +
                    indent.substring(index1 + CustomJson.NEW_LINE.length());
        }
        return output.append("\n").toString().replace(
                new String(new char[CustomJson.TAB_SIZE]
                ).replaceAll(".", " ")+"}\n", "}\n").trim();
    }
    private static String toJsonString(Object value){
        if(value == null){
            return "null";
        } else if(value instanceof java.lang.Number
        || value instanceof java.lang.Boolean){
            return value.toString();
        } else if(value instanceof java.lang.String){
            return "\"" + value + "\"";
        } else if(value instanceof java.lang.Object[]){
            int i = 0;
            StringBuilder str = new StringBuilder("[");
            for(i = 0; i < ((Object[])value).length - 1; ++i){
                str.append(CustomJson.toJsonString(
                        ((Object[])value)[i])).append(", ");
            }
            return str.append(CustomJson.toJsonString(
                    ((Object[])value)[i+1])).append("]").toString();
        } else if(value instanceof CustomJson){
            return CustomJson.toJsonString((CustomJson)value);
        }
        return null;
    }
    private static String toJsonString(CustomJson value){
        StringBuilder str = new StringBuilder("{");
        for(Map.Entry entry : value.json.entrySet()){
            str.append(CustomJson.NEW_LINE).append('"').append(
                    entry.getKey()).append("\": ").append(
                    CustomJson.toJsonString(entry.getValue())).append(",");
        }
        return str.deleteCharAt(str.length()-1).append(
                CustomJson.NEW_LINE).append("}").toString();
    }
    
    private Map<String, Object> json = new HashMap<String, Object> ();
    public CustomJson(){
        
    }
    
    public CustomJson add(String name, BigDecimal value){
        this.json.put(name, value);
        return this;
    }
    public CustomJson add(String name, BigInteger value){
        this.json.put(name, value);
        return this;
    }
    public CustomJson add(String name, boolean value){
        this.json.put(name, value);
        return this;
    }
    public CustomJson add(String name, double value){
        this.json.put(name, value);
        return this;
    }
    public CustomJson add(String name, int value){
        this.json.put(name, value);
        return this;
    }
    public CustomJson add(String name, Object[] value){
        return this;
    }
    public CustomJson add(String name, CustomJson value){
        this.json.put(name, value);
        return this;
    }
    public CustomJson add(String name, long value){
        this.json.put(name, value);
        return this;
    }
    public CustomJson add(String name, String value){
        this.json.put(name, value);
        return this;
    }
    public CustomJson addNull(String name){
        this.json.put(name, null);
        return this;
    }
    
    public Object get(String name){
        return this.json.get(name);
    }
    public boolean containsKey(String name){
        return this.json.containsKey(name);
    }
    public boolean isNull(String name){
        return (this.json.containsKey(name) && this.json.get(name) == null);
    }
}